home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_09_02
/
9n02076a
< prev
next >
Wrap
Text File
|
1990-12-16
|
34KB
|
1,056 lines
/*
* 10-Oct-1990 - created
*/
/******************************************************
*
* Module: olist.c
*
* Purpose: Functions to manage ordered lists using
* skip lists.
*
* (c) Copyright 1990 Kenneth L. Grogan, Jr.
*
* You have permission to use this code for personal,
* non-commercial purposes only. Any other use of this
* code is prohibitted without the expressed written
* consent of Kenneth L. Grogan, Jr.
*
******************************************************/
/* don't include externals */
#define OLIST_X
#include "local.h"
#include "olist.h"
#include "_olist.h"
/* random level factor p */
#define P_FACTOR 0.25
#define P_LEVEL (P_FACTOR * RAND_MAX)
/* 8 levels will accomodate */
/* 65536 items per list */
/* for P_FACTOR = .25 */
#define MAX_LEVEL 8
#define this ((SKIPLIST_T *)skip_list)
#define OLIST_IS_INVALID(sl) ((sl) == NULL)
/* get appropriate nil node */
#define NIL(sl) (nil_node[(sl)->key_type])
/* skip list node */
struct sl_node
{
/* array of ptrs to nodes */
struct sl_node **next;
SL_KEY key;
void *client_data;
};
typedef struct sl_node SL_NODE;
/* skip list level */
typedef ubyte SL_LEVEL;
/* skip list */
typedef struct
{
SL_NODE *header;
SL_NODE *current;
size_t size;
OLIST_KEY_T key_type;
SL_LEVEL highest_level;
int (*compare_func)();
} SKIPLIST_T;
/* maximum key values */
static SL_KEY max_key_value[OLIST_NUM_KEY_TYPES];
/* nil pointers by key */
static SL_NODE *nil_node[OLIST_NUM_KEY_TYPES];
/* global error flag */
int olist_errno;
/* static prototypes */
#include "__olist.h"
/*********************************************************
* olist_new:
*
* Create a new skip list. The new list will contain no
* nodes except the header node.
*
* Returns a pointer to the new list, or NULL if an
* error occurs.
*********************************************************/
OLIST olist_new (key_type, compare_func)
OLIST_KEY_T key_type;
int (*compare_func)();
{
register index_t ii;
OLIST skip_list;
SL_KEY header_key;
SL_NODE *header;
static bool first_time = TRUE;
/* initialize */
if (first_time)
{
first_time = FALSE;
SET_MAXIMUM_KEY_VALUES();
if ( ! olist_make_nil_nodes())
{
olist_errno = OLIST_NO_MEMORY;
return (NULL);
}
/* seed random generator */
RANDOMIZE();
}
/* check key argument */
if ((key_type >= MIN_KEY) && (key_type <= MAX_KEY))
{
/* make the list header node */
header = olist_make_node(MAX_LEVEL, header_key, NULL);
if (header != NULL)
{
/* make the new skip list */
skip_list = (OLIST)malloc(sizeof(SKIPLIST_T));
if (skip_list != NULL)
{
this->header = header;
this->key_type = key_type;
this->compare_func = compare_func;
/* the list starts empty */
olist_empty(skip_list);
/* return the new skip list */
olist_errno = OLIST_SUCCESS;
return (skip_list);
}
else
{
free(header);
olist_errno = OLIST_NO_MEMORY;
}
}
else
{
olist_errno = OLIST_NO_MEMORY;
}
}
else
{
/* invalid key type */
olist_errno = OLIST_INVALID_TYPE;
}
return (NULL);
}
/***********************************************************
* olist_kill:
*
* Destroy the specified skip list by freeing all of its
* associated memory.
*
* Returns TRUE if successful, otherwise FALSE.
**********************************************************/
bool olist_kill (skip_list)
OLIST skip_list;
{
olist_errno = OLIST_SUCCESS;
/* check for valid skip list */
if (OLIST_IS_INVALID(this))
{
olist_errno = OLIST_INVALID;
return (FALSE);
}
/* free each skip list nodes */
olist_free_all(skip_list);
/* free the list header */
free(this->header->next);
free(this->header);
/* prevent further access */
this->key_type = OLIST_NO_KEY;
/* free the skip list */
free(this);
/* skip list has been killed */
return (TRUE);
}
/***********************************************************
* olist_size:
* Return the number of nodes in the specified skip list.
**********************************************************/
size_t olist_size (skip_list)
OLIST skip_list;
{
olist_errno = OLIST_SUCCESS;
/* check for valid skip list */
if (OLIST_IS_INVALID(this))
{
olist_errno = OLIST_INVALID;
return (NULL);
}
/* return the list size */
return (this->size);
}
/***********************************************************
* olist_key_type:
* Return the key type for the specified skip list.
**********************************************************/
OLIST_KEY_T olist_key_type (skip_list)
OLIST skip_list;
{
olist_errno = OLIST_SUCCESS;
/* check for valid skip list */
if (OLIST_IS_INVALID(this))
{
olist_errno = OLIST_INVALID;
return (OLIST_NO_KEY);
}
/* return the list key type */
return (this->key_type);
}
/***********************************************************
* olist_add:
*
* Add the specified client data to the specified skip list.
* The argument replace_data has the following effect:
*
* value | key already in the list | key not in the list
* -----------------------------------------------------------
* TRUE | replace client data for key | add key to the list
* FALSE | return KEY_EXISTS error | add key to the list
*
* Returns TRUE if the data was inserted or replaced,
* otherwise FALSE.
**********************************************************/
bool olist_add (skip_list, key_type, inkey, client_data,
replace_data)
OLIST skip_list;
OLIST_KEY_T key_type;
void *inkey;
void *client_data;
bool replace_data;
{
register index_t ii;
SL_LEVEL new_level;
SL_KEY search_key;
SL_NODE *new_node;
SL_NODE *update_node[MAX_LEVEL];
olist_errno = OLIST_SUCCESS;
/* check for valid skip list */
if (OLIST_IS_INVALID(this) ||
(KEY_IS_INVALID(this, key_type, inkey)))
{
olist_errno = OLIST_INVALID;
return (FALSE);
}
/* get the appropriate key */
GET_KEY(search_key, key_type, inkey);
/* start with the highest */
/* level in the header node */
new_node = this->header;
ii = this->highest_level + 1;
do {
--ii;
/* get key before search key */
while (KEY_LT(this, new_node